package com.rm.zeyou.service.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.rm.zeyou.constant.CommonConstants;
import com.rm.zeyou.constant.NumberConstants;
import com.rm.zeyou.constant.OrderConstants;
import com.rm.zeyou.constant.PayConstants;
import com.rm.zeyou.entity.*;
import com.rm.zeyou.exception.ErrorCodeException;
import com.rm.zeyou.exception.ErrorCodeExceptionEnum;
import com.rm.zeyou.mapper.*;
import com.rm.zeyou.pay.alipay.service.AlipayService;
import com.rm.zeyou.pay.wxpay.service.WechatPayService;
import com.rm.zeyou.pay.wxpay.vo.WeChatRefundReturnVO;
import com.rm.zeyou.pay.wxpay.vo.WeChatRefundVO;
import com.rm.zeyou.response.ApiRestResponse;
import com.rm.zeyou.service.RefundOrderService;
import com.rm.zeyou.service.TechnicianItemOrderService;
import com.rm.zeyou.service.UserItemOrderService;
import com.rm.zeyou.util.check.CheckEmptyUtil;
import com.rm.zeyou.util.gaode.GaoDeUtil;
import com.rm.zeyou.util.random.RandomUtils;
import com.rm.zeyou.vo.request.*;
import com.rm.zeyou.vo.response.*;
import com.rm.zeyou.voice.VoiceUtil;
import com.rm.zeyou.voice.vo.request.MiddleNumberAXBVo;
import com.rm.zeyou.voice.vo.request.MiddleNumberUnbindVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * <p>
 * 用户订单表 服务实现类
 * </p>
 *
 * @author YanYang
 * @since 2025-03-12 15:55:09
 */
@Slf4j
@Service
public class TechnicianItemOrderServiceImpl extends ServiceImpl<TechnicianItemOrderMapper, TechnicianItemOrder> implements TechnicianItemOrderService {
    @Resource
    private TechnicianItemOrderMapper technicianItemOrderMapper;
    @Resource
    private VoiceUtil voiceUtil;
    @Resource
    private TechnicianAppraiseMapper technicianAppraiseMapper;
    @Resource
    private RefundOrderService refundOrderService;
    @Resource
    private GaoDeUtil gaoDeUtil;
    @Resource
    private UserItemOrderMapper userItemOrderMapper;
    @Resource
    private TechnicianConsumeDetailMapper technicianConsumeDetailMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private UserConsumeDetailMapper userConsumeDetailMapper;
    @Resource
    private GradeConfigMapper gradeConfigMapper;
    @Resource
    private OrderDictConfigMapper orderDictConfigMapper;
    @Resource
    private UserItemOrderService userItemOrderService;
    @Resource
    private VoiceTemplateConfigMapper voiceTemplateConfigMapper;
    @Resource
    private MiddleRelationMapper middleRelationMapper;
    @Resource
    private WechatPayService wechatPayService;
    @Resource
    private AlipayService alipayService;

    @Override
    public ApiRestResponse<PageInfo<SelectTechnicianOrderListResponseVo>> selectTechnicianOrderList(Technician technician, SelectTechnicianOrderListVo selectVo) {
        List<SelectTechnicianOrderListResponseVo> voList = new ArrayList<>();
        PageHelper.startPage(selectVo.getPageNum(), selectVo.getPageSize());
        List<SelectTechnicianOrderListResponseVo> selectTechnicianOrderListResponseVos = technicianItemOrderMapper.selectTechnicianOrderList(technician.getId(), selectVo.getStatus());
        if (!CheckEmptyUtil.isEmpty(selectTechnicianOrderListResponseVos)) {
            PageInfo<SelectTechnicianOrderListResponseVo> source = new PageInfo<>(selectTechnicianOrderListResponseVos);
            PageInfo<SelectTechnicianOrderListResponseVo> target = new PageInfo<>();
            BeanUtils.copyProperties(source, target);
            for (SelectTechnicianOrderListResponseVo technicianOrder : source.getList()) {
                SelectTechnicianOrderListResponseVo vo = new SelectTechnicianOrderListResponseVo();
                vo.setOrderNo(technicianOrder.getOrderNo());
                vo.setItemName(technicianOrder.getItemName());
                vo.setCarFee(technicianOrder.getCarFee());
                vo.setPayTime(technicianOrder.getPayTime());
                vo.setCustomerName(technicianOrder.getCustomerName());
                vo.setItemNum(technicianOrder.getItemNum());
                vo.setTotalPrice(technicianOrder.getTotalPrice());
                vo.setCustomerAddress(technicianOrder.getCustomerAddress());
                vo.setOrderStatus(technicianOrder.getOrderStatus());
                vo.setTid(technicianOrder.getTid());
                vo.setUserId(technicianOrder.getUserId());
                vo.setOverViewCount(technicianAppraiseMapper.selectCount(new LambdaQueryWrapper<TechnicianAppraise>().eq(TechnicianAppraise::getUserId, technicianOrder.getUserId())).intValue());
                if (technicianOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_ACCEPTANCE)) {
                    //待接单
                    //vo.setReceivingWaitTime();
                    String technicianTakeOrderTime = orderDictConfigMapper.getTechnicianTakeOrderTime();
                    //String technicianTakeOrderTime = dictConfigMapper.getTechnicianTakeOrderTime();
                    long between = DateUtil.between(new Date(), DateUtil.offsetMinute(technicianOrder.getPayTime(), Integer.parseInt(technicianTakeOrderTime)), DateUnit.SECOND, false);
                    vo.setReceivingOrdersTime(between > 0 ? between : 0);


                }

                if (technicianOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_END)) {
                    Integer orderTotalServiceTime = userItemOrderService.sumOrderTotalServiceTime(technicianOrder.getOrderNo());
                    log.info("总服务时长:{}", orderTotalServiceTime);
                    long over = DateUtil.between(new Date(), DateUtil.offsetMinute(technicianOrder.getStartServiceTime(), orderTotalServiceTime), DateUnit.SECOND, false);
                    vo.setOverTime(over);
                }
                voList.add(vo);
            }
            target.setList(voList);
            return ApiRestResponse.success(target);
        } else {
            return ApiRestResponse.success(new PageInfo<>());
        }
    }

    @Override
    public ApiRestResponse<SelectTechnicianOrderDetailsResponseVo> selectTechnicianOrderDetails(Technician technician, String orderNo) {
        SelectTechnicianOrderDetailsResponseVo vo = new SelectTechnicianOrderDetailsResponseVo();
        TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOne(new LambdaQueryWrapper<TechnicianItemOrder>().eq(TechnicianItemOrder::getOrderNo, orderNo));
        if (CheckEmptyUtil.isEmpty(technicianItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        vo.setServiceTime(technicianItemOrder.getServiceTime());
        vo.setOrderStatus(technicianItemOrder.getOrderStatus());
        vo.setOrderNo(orderNo);
        vo.setPayType(technicianItemOrder.getPayType());
        vo.setItemName(technicianItemOrder.getItemName());
        vo.setItemTime(technicianItemOrder.getItemTime());
        vo.setOrderNum(technicianItemOrder.getOrderNum());
        vo.setModeTravel(technicianItemOrder.getModeTravel());
        vo.setDistance(technicianItemOrder.getDistance());
        vo.setCarFare(technicianItemOrder.getOrderFarePrice());
        vo.setDiscountPrice(technicianItemOrder.getDiscountPrice());
        vo.setOrderTotalPrice(technicianItemOrder.getOrderTotalPrice());
        vo.setCustomerName(technicianItemOrder.getAddressUserName());
        String middleNumber = voiceTemplateConfigMapper.selectOneData("middleNumber");
        //MiddleRelation middleRelation = middleRelationMapper.selectOne(new LambdaQueryWrapper<MiddleRelation>()
        //        .eq(MiddleRelation::getTid, technician.getId())
        //        .eq(MiddleRelation::getUserId,technicianItemOrder.getUserId()));
        //if (CheckEmptyUtil.isEmpty(middleRelation)){
        //    middleNumber = technicianItemOrder.getAddressTel();
        //}
        vo.setCustomerTel(middleNumber);
        //vo.setCustomerTel(technicianItemOrder.getAddressTel());
        vo.setCustomerAddress(technicianItemOrder.getAddressDetail());
        vo.setOrderRemark(technicianItemOrder.getOrderRemark());
        vo.setPlaceOrderTime(technicianItemOrder.getPlaceOrderTime());
        vo.setPayTime(technicianItemOrder.getPayTime());
        vo.setTakeOrderTime(technicianItemOrder.getTakeOrderTime());
        vo.setProceedTime(technicianItemOrder.getProceedTime());
        vo.setArriveTime(technicianItemOrder.getArriveTime());
        vo.setStartServiceTime(technicianItemOrder.getStartServiceTime());
        vo.setStopServiceTime(technicianItemOrder.getStopServiceTime());
        vo.setCancelTime(technicianItemOrder.getCancelTime());

        vo.setUserLongLat(gaoDeUtil.geoCode(technicianItemOrder.getAddressDetail()));
        //vo.setTechnicianLongLat(gaoDeUtil.geoCode(technicianItemOrder.getArriveAddress()));
        vo.setTechnicianLongLat(technician.getLongitude() + "," + technician.getLatitude());
        if (technicianItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_END)) {
            Integer orderTotalServiceTime = userItemOrderService.sumOrderTotalServiceTime(technicianItemOrder.getOrderNo());
            long over = DateUtil.between(new Date(), DateUtil.offsetMinute(technicianItemOrder.getStartServiceTime(), orderTotalServiceTime), DateUnit.SECOND, false);
            vo.setOverTime(over);
        }
        //升级项目
        List<UpgradeOrderDetail> upgradeOrderDetailList = new ArrayList<>();
        List<UserItemOrder> upgradeOrders = userItemOrderMapper.selectList(new LambdaQueryWrapper<UserItemOrder>()
                .eq(UserItemOrder::getPartnerOrderNo, orderNo)
                .eq(UserItemOrder::getTid, technician.getId())
                .eq(UserItemOrder::getOrderType, NumberConstants.TWO_CONSTANTS)
                .orderByDesc(UserItemOrder::getPayTime)
                .notIn(UserItemOrder::getOrderStatus, OrderConstants.ORDER_STATUS_UPGRADES_NOT_PAID, OrderConstants.ORDER_STATUS_CANCELLED, OrderConstants.ORDER_STATUS_OVER)
        );
        if (!CheckEmptyUtil.isEmpty(upgradeOrders)) {
            upgradeOrders.forEach(item -> {
                UpgradeOrderDetail detail = new UpgradeOrderDetail();
                BeanUtils.copyProperties(item, detail);
                detail.setOldItemName(technicianItemOrder.getItemName());
                detail.setNewItemName(item.getItemName());
                detail.setOldItemPrice(technicianItemOrder.getOrderItemPrice());
                detail.setNewItemPrice(item.getOrderItemPrice());
                detail.setDifferentPrice(item.getNeedPayPrice());
                upgradeOrderDetailList.add(detail);
            });
        }
        vo.setUpgradeOrderDetailList(upgradeOrderDetailList);

        //加钟项目
        List<BellOrderDetail> bellOrderDetailList = new ArrayList<>();
        List<TechnicianItemOrder> bellOrders = technicianItemOrderMapper.selectList(new LambdaQueryWrapper<TechnicianItemOrder>()
                .eq(TechnicianItemOrder::getPartnerOrderNo, orderNo)
                .eq(TechnicianItemOrder::getTid, technician.getId())
                .eq(TechnicianItemOrder::getOrderType, NumberConstants.ONE_CONSTANTS)
                .orderByAsc(TechnicianItemOrder::getPayTime)
                .notIn(TechnicianItemOrder::getOrderStatus, OrderConstants.ORDER_STATUS_OVER, OrderConstants.ORDER_STATUS_BELL_NOT_PAID, OrderConstants.ORDER_STATUS_CANCELLED));

        if (!CheckEmptyUtil.isEmpty(bellOrders)) {
            bellOrders.forEach(item -> {
                BellOrderDetail detail = new BellOrderDetail();
                BeanUtils.copyProperties(item, detail);
                detail.setItemPrice(item.getOrderItemPrice());
                bellOrderDetailList.add(detail);
            });
        }
        vo.setBellOrderDetailList(bellOrderDetailList);


        //技师收入
        Map<String, BigDecimal> income = sumTechnicianItemIncome(technician, orderNo, upgradeOrders, bellOrders);
        BigDecimal totalIncome = income.get("total");
        BigDecimal itemIncome = income.get("item");

        vo.setProjectedRevenue(totalIncome);
        if (!CheckEmptyUtil.isEmpty(upgradeOrders) || !CheckEmptyUtil.isEmpty(bellOrders)) {
            //修改技师项目收入  车费收入不变
            TechnicianConsumeDetail technicianConsumeDetail = technicianConsumeDetailMapper.selectOne(new LambdaQueryWrapper<TechnicianConsumeDetail>()
                    .eq(TechnicianConsumeDetail::getOrderNo, technicianItemOrder.getOrderNo()));
            technicianConsumeDetail.setItemRevenue(itemIncome);
            technicianConsumeDetailMapper.updateById(technicianConsumeDetail);
        }


        return ApiRestResponse.success(vo);
    }


    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public ApiRestResponse<Integer> takeOrder(Technician technician, TakeOrderVo takeOrderVo) throws Exception {
        TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOne(new LambdaQueryWrapper<TechnicianItemOrder>().eq(TechnicianItemOrder::getOrderNo, takeOrderVo.getOrderNo()));
        if (CheckEmptyUtil.isEmpty(technicianItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        if (!technicianItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_ACCEPTANCE)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.CANT_TAKE_ORDER);
        }
        //查询技师是否有在服务的订单
        Integer takeOrderCount = technicianItemOrderMapper.selectTakeOrderCount(technician.getId());
        if (takeOrderCount > 0) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.NOT_TAKE_ORDER);
        }
        String technicianTakeOrderTime = orderDictConfigMapper.getTechnicianTakeOrderTime();
        //String technicianTakeOrderTime = dictConfigMapper.getTechnicianTakeOrderTime();
        if (new Date().after(DateUtil.offsetMinute(technicianItemOrder.getPayTime(), Integer.parseInt(technicianTakeOrderTime)))) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_OVERTIME);
        }
        //UserItemOrder userItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, takeOrderVo.getOrderNo()));
        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(takeOrderVo.getOrderNo());

        userItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_PENDING_DEPARTURE);
        userItemOrderMapper.updateById(userItemOrder);
        technicianItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_PENDING_DEPARTURE);
        technicianItemOrder.setTakeOrderWaitTime(takeOrderVo.getReceivingWaitTime());
        technicianItemOrder.setTakeOrderTime(new Date());
        int update = technicianItemOrderMapper.updateById(technicianItemOrder);

        //添加技师收入 资金状态改为冻结
        TechnicianConsumeDetail technicianConsumeDetail = new TechnicianConsumeDetail();
        technicianConsumeDetail.setOrderNo(technicianItemOrder.getOrderNo());
        technicianConsumeDetail.setTid(technicianItemOrder.getTid());
        technicianConsumeDetail.setConsumeType(CommonConstants.CONSUMPTION_ADD);
        Map<String, BigDecimal> income = sumTechnicianItemIncome(technician, takeOrderVo.getOrderNo(), Collections.emptyList(), Collections.emptyList());
        //Map<String, BigDecimal> map = technicianItemIncome(technician, takeOrderVo.getOrderNo(), NumberConstants.ZERO_CONSTANTS);
        BigDecimal itemIncome = income.get("item");
        BigDecimal car = income.get("car");
        technicianConsumeDetail.setItemRevenue(itemIncome);
        technicianConsumeDetail.setFareRevenue(car);
        technicianConsumeDetail.setPriceStatus(NumberConstants.ZERO_CONSTANTS);
        technicianConsumeDetail.setConsumptionDescribe(technicianItemOrder.getItemName() + "项目收入");
        technicianConsumeDetailMapper.insert(technicianConsumeDetail);

        //绑定小号

        MiddleNumberAXBVo middleNumberAXBVo = new MiddleNumberAXBVo();
        middleNumberAXBVo.setBindNumberA(technician.getTechnicianTel());
        middleNumberAXBVo.setBindNumberB(technicianItemOrder.getAddressTel());
        middleNumberAXBVo.setTid(technicianItemOrder.getTid());
        middleNumberAXBVo.setUserId(technicianItemOrder.getUserId());
        middleNumberAXBVo.setOrderNo(technicianItemOrder.getOrderNo());
        voiceUtil.middleNumberAxb(middleNumberAXBVo);

        return ApiRestResponse.success(update);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public ApiRestResponse<Integer> leave(Technician technician, LeaveVo leaveVo) {
        TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOne(new LambdaQueryWrapper<TechnicianItemOrder>().eq(TechnicianItemOrder::getOrderNo, leaveVo.getOrderNo()));
        if (CheckEmptyUtil.isEmpty(technicianItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        if (!technicianItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_DEPARTURE)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.CANT_LEAVE);
        }
        //UserItemOrder userItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, leaveVo.getOrderNo()));
        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(leaveVo.getOrderNo());

        userItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_PENDING_ARRIVAL);
        userItemOrderMapper.updateById(userItemOrder);

        technicianItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_PENDING_ARRIVAL);
        String address = gaoDeUtil.ReGeoCode(leaveVo.getLongitude() + "," + leaveVo.getLatitude());
        technicianItemOrder.setLeaveAddress(address);
        technicianItemOrder.setProceedTime(new Date());
        int update = technicianItemOrderMapper.updateById(technicianItemOrder);
        return ApiRestResponse.success(update);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public ApiRestResponse<Integer> arrive(Technician technician, ArriveVo arriveVo) {
        TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOne(new LambdaQueryWrapper<TechnicianItemOrder>().eq(TechnicianItemOrder::getOrderNo, arriveVo.getOrderNo()));
        if (CheckEmptyUtil.isEmpty(technicianItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        if (!technicianItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_ARRIVAL)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.CANT_ARRIVAL);
        }
        //UserItemOrder userItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, arriveVo.getOrderNo()));
        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(arriveVo.getOrderNo());

        userItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_PENDING_START);
        userItemOrderMapper.updateById(userItemOrder);

        technicianItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_PENDING_START);
        //String address = gaoDeUtil.ReGeoCode(arriveVo.getLongitude() + "," + arriveVo.getLatitude());
        technicianItemOrder.setArriveAddress(arriveVo.getArrivalAddress());
        technicianItemOrder.setArriveTime(new Date());
        technicianItemOrder.setArrivePicture(arriveVo.getArrivePicture());
        technicianItemOrder.setArriveRemark(arriveVo.getArriveRemark());


        int update = technicianItemOrderMapper.updateById(technicianItemOrder);
        return ApiRestResponse.success(update);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public ApiRestResponse<Integer> startService(Technician technician, StartServiceVo startServiceVo) {
        TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOne(new LambdaQueryWrapper<TechnicianItemOrder>().eq(TechnicianItemOrder::getOrderNo, startServiceVo.getOrderNo()));
        if (CheckEmptyUtil.isEmpty(technicianItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        if (!technicianItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_START)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.CANT_START);
        }
        //查询是否有未付款的升级或者加钟订单
        int noPayOrderCount = technicianItemOrderMapper.selectCount(new LambdaQueryWrapper<TechnicianItemOrder>()
                        .eq(TechnicianItemOrder::getPartnerOrderNo, technicianItemOrder.getOrderNo())
                        .in(TechnicianItemOrder::getOrderStatus, OrderConstants.ORDER_STATUS_UPGRADES_NOT_PAID, OrderConstants.ORDER_STATUS_BELL_NOT_PAID))
                .intValue();
        if (noPayOrderCount > 0) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.NOT_PAY_ORDER);
        }

        //UserItemOrder userItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, startServiceVo.getOrderNo()));
        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(startServiceVo.getOrderNo());

        userItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_PENDING_END);
        userItemOrderMapper.updateById(userItemOrder);
        //更改下级订单状态
        userItemOrderMapper.updateOrderStatus(startServiceVo.getOrderNo(), OrderConstants.ORDER_STATUS_PENDING_END);
        technicianItemOrderMapper.updateOrderStatus(startServiceVo.getOrderNo(), OrderConstants.ORDER_STATUS_PENDING_END);

        technicianItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_PENDING_END);
        technicianItemOrder.setStartServiceWaitTime(startServiceVo.getStartWaitTime());
        technicianItemOrder.setStartServiceTime(new Date());
        int update = technicianItemOrderMapper.updateById(technicianItemOrder);


        return ApiRestResponse.success(update);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public ApiRestResponse<Integer> serviceEnd(Technician technician, ServiceEndVo serviceEndVo) throws Exception {
        TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOne(new LambdaQueryWrapper<TechnicianItemOrder>().eq(TechnicianItemOrder::getOrderNo, serviceEndVo.getOrderNo()));
        if (CheckEmptyUtil.isEmpty(technicianItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }

        if (!technicianItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_END)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.CANT_END);
        }
        //查询是否有未付款的升级或者加钟订单
        int noPayOrderCount = technicianItemOrderMapper.selectCount(new LambdaQueryWrapper<TechnicianItemOrder>()
                        .eq(TechnicianItemOrder::getPartnerOrderNo, technicianItemOrder.getOrderNo())
                        .in(TechnicianItemOrder::getOrderStatus, OrderConstants.ORDER_STATUS_UPGRADES_NOT_PAID, OrderConstants.ORDER_STATUS_BELL_NOT_PAID))
                .intValue();
        if (noPayOrderCount > 0) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.NOT_PAY_ORDER);
        }
        Integer orderTotalServiceTime = userItemOrderService.sumOrderTotalServiceTime(serviceEndVo.getOrderNo());

        if (DateUtil.offsetMinute(technicianItemOrder.getStartServiceTime(), orderTotalServiceTime).isAfter(new Date())) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.SERVICE_TIME_NOTFINISH);
        }
        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(serviceEndVo.getOrderNo());
        //UserItemOrder userItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, serviceEndVo.getOrderNo()));
        userItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_PENDING_CONFIRMED_PAYMENT);
        userItemOrderMapper.updateById(userItemOrder);
        //更改下级订单状态
        userItemOrderMapper.updateOrderStatus(serviceEndVo.getOrderNo(), OrderConstants.ORDER_STATUS_PENDING_CONFIRMED_PAYMENT);
        technicianItemOrderMapper.updateOrderStatus(serviceEndVo.getOrderNo(), OrderConstants.ORDER_STATUS_PENDING_CONFIRMED_PAYMENT);

        technicianItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_PENDING_CONFIRMED_PAYMENT);
        technicianItemOrder.setStopServiceTime(new Date());
        technicianItemOrder.setRealServiceTime(serviceEndVo.getRealServiceTime());
        int update = technicianItemOrderMapper.updateById(technicianItemOrder);


        //升级
        List<UserItemOrder> upgradeOrders = userItemOrderMapper.selectList(new LambdaQueryWrapper<UserItemOrder>()
                .eq(UserItemOrder::getPartnerOrderNo, serviceEndVo.getOrderNo())
                .eq(UserItemOrder::getTid, technician.getId())
                .eq(UserItemOrder::getOrderType, NumberConstants.TWO_CONSTANTS)
                .orderByDesc(UserItemOrder::getPayTime)
                .notIn(UserItemOrder::getOrderStatus, OrderConstants.ORDER_STATUS_UPGRADES_NOT_PAID, OrderConstants.ORDER_STATUS_CANCELLED, OrderConstants.ORDER_STATUS_OVER)
        );

        //加钟项目
        List<TechnicianItemOrder> bellOrders = technicianItemOrderMapper.selectList(new LambdaQueryWrapper<TechnicianItemOrder>()
                .eq(TechnicianItemOrder::getPartnerOrderNo, serviceEndVo.getOrderNo())
                .eq(TechnicianItemOrder::getTid, technician.getId())
                .eq(TechnicianItemOrder::getOrderType, NumberConstants.ONE_CONSTANTS)
                .orderByAsc(TechnicianItemOrder::getPayTime)
                .notIn(TechnicianItemOrder::getOrderStatus, OrderConstants.ORDER_STATUS_OVER, OrderConstants.ORDER_STATUS_BELL_NOT_PAID, OrderConstants.ORDER_STATUS_CANCELLED));

        Map<String, BigDecimal> income = sumTechnicianItemIncome(technician, serviceEndVo.getOrderNo(), upgradeOrders, bellOrders);
        BigDecimal itemIncome = income.get("item");
        if (!CheckEmptyUtil.isEmpty(upgradeOrders) || !CheckEmptyUtil.isEmpty(bellOrders)) {

            //    //修改技师项目收入  车费收入不变
            TechnicianConsumeDetail technicianConsumeDetail = technicianConsumeDetailMapper.selectOne(new LambdaQueryWrapper<TechnicianConsumeDetail>()
                    .eq(TechnicianConsumeDetail::getOrderNo, technicianItemOrder.getOrderNo()));
            technicianConsumeDetail.setItemRevenue(itemIncome);
            technicianConsumeDetailMapper.updateById(technicianConsumeDetail);
        }

        //解绑技师与用户的号码
        MiddleNumberUnbindVo middleNumberUnbindVo = new MiddleNumberUnbindVo();
        middleNumberUnbindVo.setBindNumberA(technician.getTechnicianTel());
        middleNumberUnbindVo.setBindNumberB(technicianItemOrder.getAddressTel());
        voiceUtil.middleNumberUnbind(middleNumberUnbindVo);

        ////将技师资金状态解冻
        //TechnicianConsumeDetail technicianConsumeDetail = technicianConsumeDetailMapper.selectOne(new LambdaQueryWrapper<TechnicianConsumeDetail>().eq(TechnicianConsumeDetail::getOrderNo, serviceEndVo.getOrderNo()));
        //technicianConsumeDetail.setPriceStatus(NumberConstants.ONE_CONSTANTS);
        //technicianConsumeDetailMapper.updateById(technicianConsumeDetail);
        //
        //// 修改技师等级
        //technicianConsumeDetailService.updateTechnicianConsumeGrade(technician);

        return ApiRestResponse.success(update);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public ApiRestResponse<Integer> technicianAppraise(Technician technician, TechnicianAppraiseVo technicianAppraiseVo) {
        TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOne(new LambdaQueryWrapper<TechnicianItemOrder>().eq(TechnicianItemOrder::getOrderNo, technicianAppraiseVo.getOrderNo()));
        if (CheckEmptyUtil.isEmpty(technicianItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        if (!technicianItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_EVALUATION)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.CANT_APPRAISE);
        }
        //UserItemOrder userItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>().eq(UserItemOrder::getOrderNo, technicianAppraiseVo.getOrderNo()));
        //userItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_OVER);
        //userItemOrderMapper.updateById(userItemOrder);

        //更改下级订单状态
        //userItemOrderMapper.updateOrderStatus(technicianAppraiseVo.getOrderNo(), OrderConstants.ORDER_STATUS_OVER);
        technicianItemOrderMapper.updateOrderStatus(technicianAppraiseVo.getOrderNo(), OrderConstants.ORDER_STATUS_OVER);

        technicianItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_OVER);
        technicianItemOrderMapper.updateById(technicianItemOrder);

        TechnicianAppraise technicianAppraise = new TechnicianAppraise();
        technicianAppraise.setTechnicianId(technician.getId());
        technicianAppraise.setUserId(technicianItemOrder.getUserId());
        technicianAppraise.setOrderNo(technicianItemOrder.getOrderNo());
        technicianAppraise.setExertionAreas(technicianAppraiseVo.getExertionAreas());
        technicianAppraise.setStressed(technicianAppraiseVo.getStressed());
        technicianAppraise.setAddressType(technicianAppraiseVo.getAddressType());
        technicianAppraise.setCustomerSex(technicianAppraiseVo.getCustomerSex());
        technicianAppraise.setCustomerAge(technicianAppraiseVo.getCustomerAge());
        technicianAppraise.setRemark(technicianAppraiseVo.getRemark());
        technicianAppraise.setDangerousLeave(technicianAppraiseVo.getDangerousLeave());
        technicianAppraise.setDangerousRemark(technicianAppraiseVo.getDangerousRemark());
        int insert = technicianAppraiseMapper.insert(technicianAppraise);


        return ApiRestResponse.success(insert);
    }

    @Override
    public ApiRestResponse<TechnicianCancelOrderDetailResponseVo> technicianCancelOrderDetail(Technician technician, String orderNo) {
        TechnicianCancelOrderDetailResponseVo vo = new TechnicianCancelOrderDetailResponseVo();


        TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOne(new LambdaQueryWrapper<TechnicianItemOrder>().eq(TechnicianItemOrder::getOrderNo, orderNo));
        if (CheckEmptyUtil.isEmpty(technicianItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        if (!technicianItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_ACCEPTANCE) &&
                !technicianItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_START)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.CANT_CANCEL_ORDER);
        }
        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(orderNo);

        //UserItemOrder userItemOrder = userItemOrderMapper.selectOne(new LambdaQueryWrapper<UserItemOrder>()
        //        .eq(UserItemOrder::getOrderNo, orderNo));
        Map<String, BigDecimal> map = refundOrderService.sumRefundPrice(userItemOrder);
        vo.setItemName(technicianItemOrder.getItemName());
        vo.setItemPicture(technicianItemOrder.getItemPicture());
        vo.setItemTime(technicianItemOrder.getItemTime());
        vo.setItemPrice(technicianItemOrder.getOrderItemPrice());
        vo.setApplyRefundPrice(technicianItemOrder.getOrderTotalPrice());
        vo.setCanRefundPrice(map.get("refundPrice"));
        vo.setOrderNum(technicianItemOrder.getOrderNum());

        return ApiRestResponse.success(vo);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public ApiRestResponse<Integer> technicianCancelOrder(Technician technician, TechnicianCancelOrderVo technicianCancelOrderVo) throws Exception {
        TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOne(new LambdaQueryWrapper<TechnicianItemOrder>()
                .eq(TechnicianItemOrder::getOrderNo, technicianCancelOrderVo.getOrderNo()));
        if (CheckEmptyUtil.isEmpty(technicianItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        if (!technicianItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_ACCEPTANCE) &&
                !technicianItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_START)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.CANT_CANCEL_ORDER);
        }
        if (new Date().after(DateUtil.offsetMinute(technicianItemOrder.getArriveTime(), 20))) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.CANT_CANCEL_ORDER);
        }

        UserItemOrder userItemOrder = userItemOrderMapper.selectOneByOrderNo(technicianCancelOrderVo.getOrderNo());

        Map<String, BigDecimal> map = refundOrderService.sumRefundPrice(userItemOrder);
        BigDecimal canRefundPrice = map.get("refundPrice");
        //修改订单状态
        userItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_CANCELLED);
        userItemOrderMapper.updateById(userItemOrder);

        if (!technicianItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_ACCEPTANCE)){
            //将之前的路费删除  并添加新的路费
            BigDecimal technicianGet = map.get("technicianGet");
            Integer deleted = technicianConsumeDetailMapper.deleteByOrderNo(technicianCancelOrderVo.getOrderNo());
            if (deleted <= 0) {
                throw new ErrorCodeException(ErrorCodeExceptionEnum.CANCEL_FAIL);
            }
            if (technicianGet.compareTo(BigDecimal.ZERO) > 0) {
                //添加技师收入 资金状态改为冻结
                TechnicianConsumeDetail technicianConsumeDetail = new TechnicianConsumeDetail();
                technicianConsumeDetail.setOrderNo(technicianItemOrder.getOrderNo());
                technicianConsumeDetail.setTid(technicianItemOrder.getTid());
                technicianConsumeDetail.setConsumeType(CommonConstants.CONSUMPTION_ADD);
                technicianConsumeDetail.setItemRevenue(BigDecimal.ZERO);
                technicianConsumeDetail.setFareRevenue(technicianGet);
                technicianConsumeDetail.setPriceStatus(NumberConstants.ONE_CONSTANTS);
                technicianConsumeDetail.setConsumptionDescribe(technicianItemOrder.getItemName() + "项目收入");
                technicianConsumeDetailMapper.insert(technicianConsumeDetail);
            }
            //解绑技师与用户的号码
            MiddleNumberUnbindVo middleNumberUnbindVo = new MiddleNumberUnbindVo();
            middleNumberUnbindVo.setBindNumberA(technician.getTechnicianTel());
            middleNumberUnbindVo.setBindNumberB(technicianItemOrder.getAddressTel());
            voiceUtil.middleNumberUnbind(middleNumberUnbindVo);
        }

        //technicianItemOrderMapper.updateStatus(technicianCancelOrderVo.getOrderNo(),OrderConstants.ORDER_STATUS_CANCELLED);
        technicianItemOrder.setOrderStatus(OrderConstants.ORDER_STATUS_CANCELLED);
        technicianItemOrder.setCancelTime(new Date());
        technicianItemOrder.setCancelReason(technicianCancelOrderVo.getCancelReason());
        technicianItemOrder.setCancelDescribe(technicianCancelOrderVo.getCancelDescribe());
        int update = technicianItemOrderMapper.updateById(technicianItemOrder);
        //将钱退给用户
        refundUser(technicianItemOrder, canRefundPrice);
        return ApiRestResponse.success(update);
    }

    /**
     * 用户退款
     *
     * @param technicianItemOrder
     * @param price
     * @Date 2025 4月 02 09:10
     */
    @Override
    public void refundUser(TechnicianItemOrder technicianItemOrder, BigDecimal price) throws Exception {
        if (price.compareTo(BigDecimal.ZERO) > 0) {
            String refundOrderNo = RandomUtils.getOrderNo();
            if (technicianItemOrder.getPayType().equals(PayConstants.BALANCE)) {
                Integer addBalance = userMapper.addBalance(technicianItemOrder.getUserId(), price);
                if (addBalance > 0) {
                    UserConsumeDetail userConsumeDetail = new UserConsumeDetail();
                    userConsumeDetail.setOrderNo(technicianItemOrder.getOrderNo());
                    userConsumeDetail.setUserId(technicianItemOrder.getUserId());
                    userConsumeDetail.setConsumptionPrice(price);
                    userConsumeDetail.setConsumptionType(CommonConstants.CONSUMPTION_REFUND);
                    userConsumeDetail.setConsumptionDescribe("取消订单");
                    userConsumeDetailMapper.insert(userConsumeDetail);
                }
            } else if (technicianItemOrder.getPayType().equals(PayConstants.WX)) {
                //BigDecimal totalPrice = technicianItemOrder.getOrderTotalPrice();
                WeChatRefundVO refundVO = new WeChatRefundVO();
                refundVO.setOut_refund_no(refundOrderNo);
                refundVO.setOut_trade_no(technicianItemOrder.getOrderNo());
                WeChatRefundVO.amount amount = refundVO.new amount();
                amount.setTotal(technicianItemOrder.getOrderTotalPrice().multiply(new BigDecimal(100)).intValue());
                amount.setRefund(price.multiply(new BigDecimal(100)).intValue());
                refundVO.setAmount(amount);
                log.info("微信退款入参:{}", JSON.toJSONString(refundVO));
                WeChatRefundReturnVO weChatRefundReturnVO = wechatPayService.refundOrder(refundVO);
                log.info("微信退款结果:{}", JSON.toJSONString(weChatRefundReturnVO));
                if (!"SUCCESS".equals(weChatRefundReturnVO.getStatus()) && !"PROCESSING".equals(weChatRefundReturnVO.getStatus())) {
                    throw new RuntimeException("微信退款失败");
                }
            } else if (technicianItemOrder.getPayType().equals(PayConstants.ZFB)) {
                 alipayService.refund(refundOrderNo, technicianItemOrder.getOrderNo(), price.toString(), technicianItemOrder.getItemName() + "项目退款");
            }
        }
    }

    @Override
    public ApiRestResponse<String> technicianCallTel(Technician technician, TechnicianCallTelVo requestVo) throws Exception {
        TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOne(new LambdaQueryWrapper<TechnicianItemOrder>()
                .eq(TechnicianItemOrder::getOrderNo, requestVo.getOrderNo()));
        if (CheckEmptyUtil.isEmpty(technicianItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }

        String middleNumber = voiceTemplateConfigMapper.selectOneData("middleNumber");
        MiddleRelation middleRelation = middleRelationMapper.selectOne(new LambdaQueryWrapper<MiddleRelation>()
                .eq(MiddleRelation::getTid, technician.getId()));
        if (CheckEmptyUtil.isEmpty(middleRelation)) {
            middleNumber = technician.getTechnicianTel();
        }
        //MiddleNumberAXBVo middleNumberAXBVo = new MiddleNumberAXBVo();
        //middleNumberAXBVo.setBindNumberA(technician.getTechnicianTel());
        //middleNumberAXBVo.setBindNumberB(technicianItemOrder.getAddressTel());
        //middleNumberAXBVo.setTid(technicianItemOrder.getTid());
        //middleNumberAXBVo.setUserId(technicianItemOrder.getUserId());
        //middleNumberAXBVo.setOrderNo(technicianItemOrder.getOrderNo());
        //return ApiRestResponse.success(voiceUtil.middleNumberAxb(middleNumberAXBVo));
        return ApiRestResponse.success(middleNumber);
    }

    @Override
    public ApiRestResponse<Integer> technicianVoice(Technician technician, TechnicianVoiceVo technicianVoiceVo) {
        TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOne(new LambdaQueryWrapper<TechnicianItemOrder>()
                .eq(TechnicianItemOrder::getOrderNo, technicianVoiceVo.getOrderNo()));
        if (CheckEmptyUtil.isEmpty(technicianItemOrder)) {
            throw new ErrorCodeException(ErrorCodeExceptionEnum.ORDER_EMPTY);
        }
        String recordUrl;
        if (CheckEmptyUtil.isEmpty(technicianItemOrder.getRecordUrl())) {
            recordUrl = technicianVoiceVo.getVoiceUrl();
        } else {
            recordUrl = technicianItemOrder.getRecordUrl() + "," + technicianVoiceVo.getVoiceUrl();
        }
        technicianItemOrder.setRecordUrl(recordUrl);
        return ApiRestResponse.success(technicianItemOrderMapper.updateById(technicianItemOrder));
    }


    /**
     * 技师取消订单退款金额
     *
     * @param technicianItemOrder
     * @return
     * @Date 2025 3月 19 16:11
     */
    private Map<String, BigDecimal> cancelOrderPrice(TechnicianItemOrder technicianItemOrder) {
        Map<String, BigDecimal> map = new HashMap<>();
        //申请金额
        BigDecimal applyRefundPrice = technicianItemOrder.getOrderTotalPrice();
        //可退款金额
        BigDecimal canRefundPrice;
        if (technicianItemOrder.getOrderStatus().equals(OrderConstants.ORDER_STATUS_PENDING_ACCEPTANCE)) {
            //待接单取消订单
            //判断用户是否开通会员
            if (technicianItemOrder.getIsOpenMembership().equals(NumberConstants.ONE_CONSTANTS)) {
                canRefundPrice = technicianItemOrder.getOrderTotalPrice().subtract(technicianItemOrder.getOpenMemberPrice());
            } else {

                canRefundPrice = applyRefundPrice;
            }
        } else {
            //判断用户是否开通会员
            if (technicianItemOrder.getIsOpenMembership().equals(NumberConstants.ONE_CONSTANTS)) {
                canRefundPrice = technicianItemOrder.getOrderTotalPrice().subtract(technicianItemOrder.getOpenMemberPrice());
            } else {

                canRefundPrice = applyRefundPrice;
            }

            if (technicianItemOrder.getOrderFarePrice().compareTo(BigDecimal.ZERO) == 0) {
                //免车费
                canRefundPrice = canRefundPrice.subtract(new BigDecimal(80));
            } else {
                canRefundPrice = canRefundPrice.subtract(technicianItemOrder.getOrderFarePrice());
            }

        }
        map.put("applyRefundPrice", applyRefundPrice);
        map.put("canRefundPrice", canRefundPrice);
        return map;
    }


    private Map<String, BigDecimal> sumTechnicianItemIncome(Technician technician, String orderNo, List<UserItemOrder> upgradeOrders, List<TechnicianItemOrder> bellOrders) {
        Map<String, BigDecimal> map = new HashMap<>();
        //原项目收入
        Map<String, BigDecimal> incomeMap = technicianItemIncome(technician, orderNo, NumberConstants.ZERO_CONSTANTS);
        BigDecimal totalIncome = incomeMap.get("total");
        BigDecimal itemIncome = incomeMap.get("item");
        BigDecimal carIncome = incomeMap.get("car");
        log.info("原项目总收益：{}", totalIncome);
        log.info("原项目项目收益：{}", itemIncome);
        log.info("原项目车费收益：{}", carIncome);

        //升级项目
        BigDecimal upgradeIncome = BigDecimal.ZERO;
        if (!CheckEmptyUtil.isEmpty(upgradeOrders)) {
            log.info("升级项目条数：{}", upgradeOrders.size());
            UserItemOrder userItemOrder = upgradeOrders.get(0);
            log.info("最后一次升级项目：{}", JSON.toJSONString(userItemOrder));
            Map<String, BigDecimal> income = technicianItemIncome(technician, userItemOrder.getOrderNo(), NumberConstants.THREE_CONSTANTS);
            itemIncome = income.get("item");
        }
        log.info("升级项目收益:{}", upgradeIncome);

        //加钟项目
        List<BigDecimal> bellTotal = new ArrayList<>();
        if (!CheckEmptyUtil.isEmpty(bellOrders)) {
            TechnicianItemOrder firstOrder = bellOrders.get(0);
            //加钟第一天收益
            Map<String, BigDecimal> firstIncome = technicianItemIncome(technician, firstOrder.getOrderNo(), NumberConstants.ONE_CONSTANTS);
            bellTotal.add(firstIncome.get("item"));
            //多条加钟数据
            if (bellOrders.size() > 1) {
                //第二条之后的收益
                bellOrders.stream().skip(1).forEach(item -> {
                    Map<String, BigDecimal> secondIncome = technicianItemIncome(technician, item.getOrderNo(), NumberConstants.TWO_CONSTANTS);
                    bellTotal.add(secondIncome.get("item"));
                });
            }
        }
        log.info("加钟项目收益：{}", JSON.toJSONString(bellTotal));
        BigDecimal bellIncome = BigDecimal.ZERO;
        if (!CheckEmptyUtil.isEmpty(bellIncome)) {
            bellIncome = bellTotal.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        }
        log.info("加钟项目总收益：{}", bellIncome);

        log.info("总收益：{}", itemIncome.add(bellIncome).add(carIncome));
        log.info("总项目收益：{}", itemIncome.add(bellIncome));
        log.info("总车费收益：{}", carIncome);

        //技师预计收益
        map.put("total", itemIncome.add(bellIncome).add(carIncome));
        map.put("item", itemIncome.add(bellIncome));
        map.put("car", carIncome);
        return map;
    }

    /**
     * 计算技师项目收入
     *
     * @param orderNo
     * @param type    0=正常项目 1=第一次加钟 2=第二次加钟 3=升级套餐
     * @return
     * @Date 2025 3月 19 14:18
     */
    private Map<String, BigDecimal> technicianItemIncome(Technician technician, String orderNo, Integer type) {
        Map<String, BigDecimal> map = new HashMap<>();
        TechnicianItemOrder technicianItemOrder = technicianItemOrderMapper.selectOne(new LambdaQueryWrapper<TechnicianItemOrder>()
                .eq(TechnicianItemOrder::getOrderNo, orderNo));

        BigDecimal itemPrice = getBigDecimal(technician, type, technicianItemOrder);
        map.put("item", itemPrice);
        map.put("car", technicianItemOrder.getOrderFarePrice());
        //技师预计收益
        map.put("total", itemPrice.add(technicianItemOrder.getOrderFarePrice()));
        return map;
    }

    private BigDecimal getBigDecimal(Technician technician, Integer type, TechnicianItemOrder technicianItemOrder) {
        GradeConfig gradeConfig = gradeConfigMapper.selectById(technician.getGradeId());
        BigDecimal technicianSplitRate = getSplitRate(technician, type, gradeConfig);
        BigDecimal rate = technicianSplitRate.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
        return technicianItemOrder.getOrderItemPrice().multiply(rate);
    }

    private BigDecimal getSplitRate(Technician technician, Integer type, GradeConfig gradeConfig) {
        if (CheckEmptyUtil.isEmpty(technician.getEffectStartTime()) || CheckEmptyUtil.isEmpty(technician.getEffectEndTime())) {
            return getGradeSplitRate(type, gradeConfig);
        }
        if (DateUtil.isIn(new Date(), technician.getEffectStartTime(), technician.getEffectEndTime())) {
            return getTechnicianSplitRate(technician, type);
        }
        return getGradeSplitRate(type, gradeConfig);
    }

    private BigDecimal getGradeSplitRate(Integer type, GradeConfig gradeConfig) {
        switch (type) {
            case 1:
                return gradeConfig.getContinuationProportions();
            case 2:
                return gradeConfig.getContinuationSecondProportions();
            case 3:
                return gradeConfig.getUpgradeProportions();
            default:
                return gradeConfig.getSplitProportions();
        }
    }

    private BigDecimal getTechnicianSplitRate(Technician technician, Integer type) {
        switch (type) {
            case 1:
                return technician.getBellFirstSplitRate();
            case 2:
                return technician.getBellSecondSplitRate();
            case 3:
                return technician.getUpgradeSplitRate();
            default:
                return technician.getSplitRate();
        }
    }

}
